home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src890906.arc / ICMP.C < prev    next >
C/C++ Source or Header  |  1989-08-13  |  6KB  |  235 lines

  1. /* Internet Control Message Protocol */
  2. #include <stdio.h>
  3. #include "global.h"
  4. #include "mbuf.h"
  5. #include "internet.h"
  6. #include "timer.h"
  7. #include "iface.h"
  8. #include "ip.h"
  9. #include "icmp.h"
  10. #include "netuser.h"
  11. #include "tcp.h"
  12.  
  13. struct icmp_errors Icmp_errors;
  14. struct icmp_stats Icmp_stats;
  15.  
  16. /* Process an incoming ICMP packet */
  17. void
  18. icmp_input(bp,ip,rxbroadcast)
  19. struct mbuf *bp;    /* Pointer to ICMP message */
  20. struct ip *ip;
  21. int rxbroadcast;
  22. {
  23.     struct mbuf *tbp;
  24.     struct icmp icmp;    /* ICMP header */
  25.     struct ip oip;        /* Offending datagram header */
  26.     int16 type;        /* Type of ICMP message */
  27.     int16 length;
  28.  
  29.     if(rxbroadcast){
  30.         /* Broadcast ICMP packets are to be IGNORED !! */
  31.         Icmp_errors.bdcsts++;
  32.         free_p(bp);
  33.         return;
  34.     }
  35.     length = ip->length - IPLEN - ip->optlen;
  36.     if(cksum(NULLHEADER,bp,length) != 0){
  37.         /* Bad ICMP checksum; discard */
  38.         Icmp_errors.checksum++;
  39.         free_p(bp);
  40.         return;
  41.     }
  42.     ntohicmp(&icmp,&bp);
  43.  
  44.     /* Process the message. Some messages are passed up to the protocol
  45.      * module for handling, others are handled here.
  46.      */
  47.     type = icmp.type;
  48.     if(type < ICMP_TYPES)
  49.         Icmp_stats.input[type]++;
  50.  
  51.     switch(uchar(type)){
  52.     case TIME_EXCEED:    /* Time-to-live Exceeded */
  53.     case DEST_UNREACH:    /* Destination Unreachable */
  54.     case QUENCH:        /* Source Quench */
  55.         ntohip(&oip,&bp);    /* Extract offending IP header */
  56.         if(Icmp_trace){
  57.             printf("ICMP from %s:",inet_ntoa(ip->source));
  58.             printf(" dest %s %s",inet_ntoa(oip.dest),
  59.              smsg(Icmptypes,ICMP_TYPES,uchar(type)));
  60.             switch(uchar(type)){
  61.             case TIME_EXCEED:
  62.                 printf(" %s\n",
  63.                  smsg(Exceed,NEXCEED,uchar(icmp.code)));
  64.                 break;
  65.             case DEST_UNREACH:
  66.                 printf(" %s\n",
  67.                  smsg(Unreach,NUNREACH,uchar(icmp.code)));
  68.                 break;
  69.             default:
  70.                 printf(" %u\n",uchar(icmp.code));
  71.                 break;
  72.             }
  73.         }
  74.         switch(uchar(oip.protocol)){
  75.         case TCP_PTCL:
  76.             tcp_icmp(oip.source,oip.dest,icmp.type,icmp.code,&bp);
  77.             break;
  78.         }
  79.         break;
  80.     case ECHO:        /* Echo Request */
  81.         /* Change type to ECHO_REPLY, recompute checksum,
  82.          * and return datagram.
  83.          */
  84.         icmp.type = ECHO_REPLY;
  85.         if((tbp = htonicmp(&icmp,bp)) == NULLBUF){
  86.             free_p(bp);
  87.             return;
  88.         }
  89.         Icmp_stats.output[ECHO_REPLY]++;
  90.         ip_send(ip->dest,ip->source,ICMP_PTCL,ip->tos,0,tbp,length,0,0);
  91.         return;
  92.     case REDIRECT:        /* Redirect */
  93.     case PARAM_PROB:    /* Parameter Problem */
  94.         break;
  95.        case ECHO_REPLY:        /* Echo Reply */
  96.         echo_proc(ip->source,ip->dest,&icmp,bp);
  97.         bp = NULLBUF;    /* so it won't get freed */
  98.         break;
  99.     case TIMESTAMP:        /* Timestamp */
  100.     case TIME_REPLY:    /* Timestamp Reply */
  101.     case INFO_RQST:        /* Information Request */
  102.     case INFO_REPLY:    /* Information Reply */
  103.         break;
  104.     }
  105.     free_p(bp);
  106. }
  107. /* Return an ICMP response to the sender of a datagram.
  108.  * Unlike most routines, the callER frees the mbuf.
  109.  */
  110. int
  111. icmp_output(ip,data,type,code,args)
  112. struct ip *ip;        /* Header of offending datagram */
  113. struct mbuf *data;    /* Data portion of datagram */
  114. char type,code;        /* Codes to send */
  115. union icmp_args *args;
  116. {
  117.     struct mbuf *bp;
  118.     struct icmp icmp;    /* ICMP protocol header */
  119.     int16 dlen;        /* Length of data portion of offending pkt */
  120.     int16 length;        /* Total length of reply */
  121.  
  122.     if(ip == NULLIP)
  123.         return -1;
  124.     if(uchar(ip->protocol) == ICMP_PTCL){
  125.         /* Peek at type field of ICMP header to see if it's safe to
  126.          * return an ICMP message
  127.          */
  128.         switch(uchar(data->data[0])){
  129.         case ECHO_REPLY:
  130.         case ECHO:
  131.         case TIMESTAMP:
  132.         case TIME_REPLY:
  133.         case INFO_RQST:
  134.         case INFO_REPLY:
  135.             break;    /* These are all safe */
  136.         default:
  137.             /* Never send an ICMP error message about another
  138.              * ICMP error message!
  139.              */
  140.             Icmp_errors.noloop++;
  141.             return -1;
  142.         }
  143.     }
  144.     if(type < ICMP_TYPES)
  145.         Icmp_stats.output[type]++;
  146.  
  147.     /* Compute amount of original datagram to return.
  148.      * We return the original IP header, and up to 8 bytes past that.
  149.      */
  150.     dlen = min(8,len_mbuf(data));
  151.     length = dlen + ICMPLEN + IPLEN + ip->optlen;
  152.     /* Take excerpt from data portion */
  153.     if(data != NULLBUF && dup_p(&bp,data,0,dlen) == 0)
  154.         return -1;    /* The caller will free data */
  155.  
  156.     /* Recreate and tack on offending IP header */
  157.     if((data = htonip(ip,bp)) == NULLBUF){
  158.         free_p(bp);
  159.         return -1;
  160.     }
  161.     icmp.type = type;
  162.     icmp.code = code;
  163.     switch(uchar(icmp.type)){
  164.     case PARAM_PROB:
  165.         icmp.args.pointer = args->pointer;
  166.         break;
  167.     case REDIRECT:
  168.         icmp.args.address = args->address;
  169.         break;
  170.     case ECHO:
  171.     case ECHO_REPLY:
  172.     case INFO_RQST:
  173.     case INFO_REPLY:
  174.     case TIMESTAMP:
  175.     case TIME_REPLY:
  176.         icmp.args.echo.id = args->echo.id;
  177.         icmp.args.echo.seq = args->echo.seq;
  178.         break;
  179.     default:
  180.         icmp.args.unused = 0;
  181.         break;
  182.     }
  183.     /* Now stick on the ICMP header */
  184.     if((bp = htonicmp(&icmp,data)) == NULLBUF){
  185.         free_p(data);
  186.         return -1;
  187.     }
  188.     return ip_send(Ip_addr,ip->source,ICMP_PTCL,ip->tos,0,bp,length,0,0);
  189. }
  190. /* Generate ICMP header in network byte order, link data, compute checksum */
  191. struct mbuf *
  192. htonicmp(icmp,data)
  193. struct icmp *icmp;
  194. struct mbuf *data;
  195. {
  196.     struct mbuf *bp;
  197.     register char *cp;
  198.     int16 checksum;
  199.  
  200.     if((bp = pushdown(data,ICMPLEN)) == NULLBUF)
  201.         return NULLBUF;
  202.     cp = bp->data;
  203.  
  204.     *cp++ = icmp->type;
  205.     *cp++ = icmp->code;
  206.     cp = put16(cp,0);        /* Clear checksum */
  207.     cp = put16(cp,icmp->args.echo.id);
  208.     cp = put16(cp,icmp->args.echo.seq);
  209.  
  210.     /* Compute checksum, and stash result */
  211.     checksum = cksum(NULLHEADER,bp,len_mbuf(bp));
  212.     cp = &bp->data[2];
  213.     cp = put16(cp,checksum);
  214.  
  215.     return bp;
  216. }
  217. /* Pull off ICMP header */
  218. int
  219. ntohicmp(icmp,bpp)
  220. struct icmp *icmp;
  221. struct mbuf **bpp;
  222. {
  223.     char icmpbuf[8];
  224.  
  225.     if(icmp == (struct icmp *)NULL)
  226.         return -1;
  227.     if(pullup(bpp,icmpbuf,8) != 8)
  228.         return -1;
  229.     icmp->type = icmpbuf[0];
  230.     icmp->code = icmpbuf[1];
  231.     icmp->args.echo.id = get16(&icmpbuf[4]);
  232.     icmp->args.echo.seq = get16(&icmpbuf[6]);
  233.     return 0;
  234. }
  235.